package main

import (
	"crypto/md5"
	"os"
	pathpkg "path"

	"../pb"

	"golang.org/x/net/context"
)

const (
	DIR              = int64(1)
	FILE_NOTFINISHED = int64(2)
	FILE_FINISHED    = int64(3)
	ALL_FINISHED     = int64(4)
)

const (
	WELL  = int64(0)
	ERROR = int64(1)
)

type flieClient struct {
	name     string
	basePath string
	cli      pb.FileServiceClient
	Files    map[string]*os.File
}

func (fc *flieClient) GetFiles() error {
	x, err := fc.cli.GetFile(context.Background())
	if err != nil {
		log.Errorf("get file,error:%v", err)
		return err
	}
	req := &pb.GetFileRequest{Path: fc.name}
	err = x.Send(req)
	if err != nil {
		log.Errorf("send,error:%v", err)
		return err
	}
	for {
		resp, err := x.Recv()
		if err != nil {
			log.Errorf("recieve,error:%v", err)
			return err
		}
		path := pathpkg.Join(fc.basePath, resp.FileName)
		switch resp.Type {
		case DIR:
			err := os.MkdirAll(path, 0777)
			if err != nil {
				log.Errorf("os mkdir,error:%v", err)
				return err
			}
			req := &pb.GetFileRequest{Flag: WELL}
			x.Send(req)
		case FILE_NOTFINISHED:
			if string(MD5(resp.FileData)) != string(resp.CheckSum) {
				req := &pb.GetFileRequest{Flag: ERROR}
				x.Send(req)
				continue
			}
			if _, ok := fc.Files[resp.FileName]; !ok {
				file, err := os.OpenFile(path, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0777)
				if err != nil {
					log.Errorf("os openfile,error:%v", err)
					return err
				}
				fc.Files[resp.FileName] = file
			}
			if _, err := fc.Files[resp.FileName].Write(resp.FileData); err != nil {
				log.Errorf("file write,error:%v", err)
				return err
			}
			req := &pb.GetFileRequest{Flag: WELL}
			x.Send(req)
		case FILE_FINISHED:
			err := fc.Files[resp.FileName].Close()
			if err != nil {
				log.Errorf("file close,error:%v", err)
				return err
			}
			delete(fc.Files, resp.FileName)
			req := &pb.GetFileRequest{Flag: WELL}
			x.Send(req)
		case ALL_FINISHED:
			req := &pb.GetFileRequest{Flag: WELL}
			x.Send(req)
			x.CloseSend()
			return nil
		}
	}
}

func MD5(text []byte) []byte {
	md5Hash := md5.New()
	md5Hash.Write(text)
	return md5Hash.Sum(nil)
}
